<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>第一个GTK+程序</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, First programs in GTK+, GTK+ library, C">
<meta nam="description" content="First programs in GTK+">
<meta name="language" content="zn, en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>第一个GTK+程序</h1>


<p>
在这一章节中，我们将开始编写第一个GTK+程序。
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>

<h2>超级简单的例子</h2>

<p>
我们要“制造”一个超级简单的GTK+程序。就是显示一个空白的窗口。
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;

int main( int argc, char *argv[])
{
  GtkWidget *window;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_show(window);

  gtk_main();

  return 0;
}
</pre>

<p>
这个例子就是为我们显示了一个空白的窗口。
</p>

<pre class="code">
  gcc -o simple simple.c `pkg-config --libs --cflags gtk+-2.0`
</pre>

<p>
这就是我们用来编译这个例子的命令。下面我们将对这个简单的程序进行详细的解读。 
</p>

<pre class="explanation">
 gtk_init(&argc, &argv);
</pre>

<p>
这就是在初始化整个GTK+程序，是每一个GTK+程序必不可少的部分。 
</p>

<pre class="explanation">
 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
</pre>

<p>
这里我们首先生成了一个构件—— <b class="keyword">GtkWindow</b>. 这个窗口构件的种类是<b class="keyword">GTK_WINDOW_TOPLEVEL</b>.
. Toplevel 窗口拥有一个标题栏和边框。他们同意由窗口管理器进行管理。

</p>

<pre class="explanation">
 gtk_widget_show(window);
</pre>

<p>
在我们生成了一个窗口构件以后，必不可少的是，我们需要用这句语句来显示构件。 
</p>

<pre class="explanation">
 gtk_main();
</pre>

<p>
这句代码语句将进入“主循环”。 在这一点上，GTK+程序将安静的等待“事件”(event)的发生，以便做出相应的反应。 
</p>

<br>
<img src="../images/simple.png" alt="Simple">
<div class="figure">Figure: Simple</div>
<br>

<h2>生成一个窗口</h2>

<p>
如果我们不安排窗口的摆放位置的话，那么窗口管理器将为我们给这个窗口“安一个家”。在下个例子中，我们将走进“窗口”。
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;

int main( int argc, char *argv[])
{
  GtkWidget *window;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Center");
  gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_widget_show(window);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
      G_CALLBACK(gtk_main_quit), NULL);

  gtk_main();

  return 0;
}
</pre>

<p>
在我们上面的这个例子，我将深入了解窗口构件（window widget），为窗口构件设置标题和大小。 
</p>

<pre class="explanation">
 gtk_window_set_title(GTK_WINDOW(window), "Center");
</pre>

<p>
<b class="keyword">gtk_window_set_title()</b> 这个函数就可以为window设置一个标题，如果我们不用这个函数的话，GTK+将用源文件的名字来作为窗口的标题。 
</p>

<pre class="explanation">
 gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
</pre>

<p>
上面这个代码片段为window设置了 230x150 像素的大小。值得注意的是，我们这里提到的大小是指主窗口的大小；而不包括窗口管理器提供的修饰或者装饰的部分。 
</p>

<pre class="explanation">
 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
</pre>

<p>
这段代码把窗口设定在显示器的中央。 
</p>

<pre class="explanation">
 g_signal_connect_swapped(G_OBJECT(window), "destroy",
     G_CALLBACK(gtk_main_quit), NULL);
</pre>

<p>
在之前的例子中，我们没有设置窗口的关闭，当我按下右上角的“X”时。我们可以看到，如果是从命令行的方式来运行例子程序的话，默认情况下窗口程序并不会对你刚刚的动作作出反应（当然，最新的窗口管理器，譬如X11会强行关闭）。我们必须要明确为这个例子程序连接上一个关闭的信号（the destroy signal），就是 
<b class="keyword">gtk_main_quit()</b> 这个函数。
</p>


<h2>应用程序图标的制作</h2>

<p>
在下面的例子中，我们会进行应用程序图标的制作。大多数的窗口管理器都会把图标放置在标题栏的左上方和任务栏上。 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;

GdkPixbuf *create_pixbuf(const gchar * filename)
{
   GdkPixbuf *pixbuf;
   GError *error = NULL;
   pixbuf = gdk_pixbuf_new_from_file(filename, &amp;error);
   if(!pixbuf) {
      fprintf(stderr, "%s\n", error->message);
      g_error_free(error);
   }

   return pixbuf;
}

int main( int argc, char *argv[])
{
  GtkWidget *window;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "icon");
  gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("web.png"));
  gtk_widget_show(window);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
      G_CALLBACK(gtk_main_quit), NULL);

  gtk_main();

  return 0;
}
</pre>

<p>
上面的就是为一个填加上图标的窗口程序了.
</p>

<pre class="explanation">
 gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("web.png"));
</pre>

<p>
函数<b class="keyword">gtk_window_set_icon()</b> 是为窗口设置图标用的。函数
<b class="keyword">create_pixbuf()</b> 作用是从一个png图象文件中生成 <b class="keyword">GdkPixbuf</b> 类型数据。 

</p>

<pre class="explanation">
 pixbuf = gdk_pixbuf_new_from_file(filename, &amp;error);
</pre>

<p>
根据官方公布的文档说明，函数 <b class="keyword">gdk_pixbuf_new_from_file()</b> 一个文件中加载图象数据，从而生成一个新的 pixbuf。 至于文件中包含图象的格式，是由系统自动检测的。如果该函数返回值是NULL的话，程序就会出现错误。
</p>

<br>
<img src="../images/icon.png" alt="Icon">&nbsp;&nbsp;
<img src="../images/taskbar.png" alt="Taskbar Icon">
<div class="figure">Figure: Icon</div>
<br>



<h2>增加 和 减少</h2>

<p>
下面我们将用一个简单的示例，来完成了“GTK+程序设计初级教程”的第一阶段，在这里我们用到了三个构件：两个按钮和一个标签。这个标签将保存一个整数，两个按钮会分别增加和减少这个数。
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;

gint count = 0;
char buf[5];

void increase(GtkWidget *widget, gpointer label)
{
  count++;

  sprintf(buf, "%d", count);
  gtk_label_set_text(label, buf);
}

void decrease(GtkWidget *widget, gpointer label)
{
  count--;

  sprintf(buf, "%d", count);
  gtk_label_set_text(label, buf);
}

int main(int argc, char** argv) {

  GtkWidget *label;
  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *plus;
  GtkWidget *minus;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 180);
  gtk_window_set_title(GTK_WINDOW(window), "+-");

  frame = gtk_fixed_new();
  gtk_container_add(GTK_CONTAINER(window), frame);

  plus = gtk_button_new_with_label("+");
  gtk_widget_set_size_request(plus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), plus, 50, 20);

  minus = gtk_button_new_with_label("-");
  gtk_widget_set_size_request(minus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), minus, 50, 80);

  label = gtk_label_new("0");
  gtk_fixed_put(GTK_FIXED(frame), label, 190, 58); 

  gtk_widget_show_all(window);

  g_signal_connect(window, "destroy",
      G_CALLBACK (gtk_main_quit), NULL);

  g_signal_connect(plus, "clicked", 
      G_CALLBACK(increase), label);

  g_signal_connect(minus, "clicked", 
      G_CALLBACK(decrease), label);

  gtk_main();

  return 0;
}
</pre>

<p>
这个示例代码完的功能是：增加和减少对象GtkLabel的值。
</p>

<pre class="explanation">
 g_signal_connect(plus, "clicked", 
     G_CALLBACK(increase), label);
</pre>

<p>
我们把回调函数<b class="keyword">increase()</b>和增加按钮进行了连结。还有值得注意的是我们把label作为回调函数调用的参数。 这样的话就可以在回调函数increase()中对label进行处理。 

</p>

<pre class="explanation">
 count++;

 sprintf(buf, "%d", count);
 gtk_label_set_text(label, buf);
</pre>

<p>
在“增加”的回调函数中，增加数字。 然后在label中的数字就会随之增加。
</p>

<br>
<img src="../images/plusminus.png" alt="Increase - Decrease">
<div class="figure">Figure: Increase - Decrease</div>
<br>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified April 2, 2008  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
<span class="copyright">Translation &copy; 2008 chinalmy</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>
